#!/usr/bin/env python
# coding=UTF-8


from flask import Flask, make_response, request, session
import os
import json
import random
import string
from datetime import timedelta
from functools import wraps
import hashlib
import time


DATA_PATH = os.path.join(os.path.dirname(__file__), '..', 'data')
SECRET_KEY = 'autoClass'


def get_data(file_name):
    file_path = DATA_PATH + '/' + file_name
    with open(file_path, 'r') as f:
        user_list = json.load(f)
    return user_list


def update_data(file_name, data):
    file_path = DATA_PATH + '/' + file_name
    with open(file_path, 'w') as f:
        json.dump(data, f)


def make_resp(resp, status_code):
    response = make_response(resp, status_code)
    response.headers["Content-Type"] = "application/json"
    return response


def gen_random_string(str_len):
    '''
    返回指定长度的随机字符串
    '''
    return ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(str_len))


def get_session():
    return session.get('token')


def sign_status(ts):
    time_lag = int(time.time()) - int(ts)
    is_timeoff = (time_lag > 1200) or (time_lag < 0)
    return is_timeoff


def sort_req(req):
    s_key = sorted(req.keys(), reverse=False)
    if 'sign' in s_key:
        s_key.remove('sign')
    for k in s_key:
        if req[k] is None or not req[k]:
            s_key.remove(k)
    return s_key


def get_sign(req):
    bs = ''
    for i in sort_req(req):
        bs += '{}={}&'.format(i, req[i])
    bs += SECRET_KEY
    sign = hashlib.md5(bs.encode('utf-8')).hexdigest()
    print(sign)
    return sign


def validate_request(func):
    @wraps(func)
    def wrapper(*args, **kw):
        req = request.get_json()
        sign = req.get('sign', None)
        ts = req.get('ts', None)
        if sign != get_sign(req):
            resp = {'errorCode': 5, 'msg': "签名无效"}
            return make_resp(resp, 401)
        if sign_status(ts):
            resp = {'errorCode': 4, 'msg': "ts过期"}
            return make_resp(resp, 403)
        return func(*args, **kw)
    return wrapper


def validate_login(func):
    @wraps(func)
    def wrapper(*args, **kw):
        req_session = request.headers['session']
        if req_session != get_session():
            resp = {
                'errorCode': 1,
                'msg': "请先登陆"
            }
            status_code = 401
            return make_resp(resp, status_code)
        return func(*args, **kw)
    return wrapper


# Flask构造函数使用当前模块（__name __）的名称作为参数
app = Flask(__name__)

# 设置session在15分钟后过期
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(minutes=15)
# 设置sceret_key
app.secret_key = gen_random_string(16)


@app.route('/')  # 告诉应用程序哪个URL应该调用相关的函数
@validate_login
def index():
    return 'Hello autoClass'


@app.route('/api/login', methods=['POST'])
@validate_request
def login():
    req = request.get_json()
    name = req.get('name', None)
    passwd = req.get('passwd', None)
    if not name or not passwd:
        resp = {
            'errorCode': 1,
            'msg': "请输入用户名/密码"
        }
        status_code = 401
    else:
        result = False
        data = get_data('users.json')
        users_list = data.get('users')
        for u in users_list:
            if name == u.get('name', None):
                if passwd == u.get('passwd', None):
                    result = True
        if not result:
            resp = {
                'errorCode': 1,
                'msg': "用户名/密码错误"
            }
            status_code = 401
        else:
            session['token'] = '{}_{}'.format(name, gen_random_string(8))
            resp = {
                'errorCode': 0,
                'msg': "登陆成功"
            }
            status_code = 200
    reponse = make_resp(resp, status_code)
    reponse.headers['session'] = get_session()
    return reponse


@app.route('/api/users')
@validate_login
def get_all_users():
    data = get_data('users.json')
    resp = {
        'errorCode': 0,
        'count': len(data['users']),
        'data': data
    }
    status_code = 200
    return make_resp(resp, status_code)


@app.route('/api/users/<int:uid>')
@validate_login
def get_user(uid):
    data = get_data('users.json')
    users_list = data.get('users')
    uid_list = []
    for u in users_list:
        uid_list.append(u.get('uid'))
    if uid in uid_list:
        resp = {
            'errorCode': 0,
            'data': users_list[uid_list.index(uid)]
        }
        status_code = 200
    else:
        resp = {
            'errorCode': 1,
            'msg': 'uid {} not found'.format(uid)
        }
        status_code = 404
    return make_resp(resp, status_code)


@app.route('/api/users', methods=['POST'])
@validate_login
@validate_request
def create_user():
    req = request.get_json()
    new_uid = req.get('uid', None)
    data = get_data('users.json')
    users_list = data.get('users')
    uid_list = []
    for u in users_list:
        uid_list.append(u.get('uid'))
    if new_uid in uid_list:
        resp = {
            'errorCode': 2,
            'msg': 'uid {} is dumplicate'.format(new_uid)
        }
        status_code = 417
    elif not new_uid:
        resp = {
            'errorCode': 3,
            'msg': 'uid is required'
        }
        status_code = 401
    else:
        data.get('users').append(req)
        update_data('users.json', data)
        resp = {
            'errorCode': 0,
            'msg': 'uid {} has been added'.format(new_uid)
        }
        status_code = 200
    return make_resp(resp, status_code)


@app.route('/api/users', methods=['PUT'])
@validate_login
@validate_request
def update_user():
    req = request.get_json()
    update_uid = req.get('uid', None)
    data = get_data('users.json')
    users_list = data.get('users')
    uid_list = []
    for u in users_list:
        uid_list.append(u.get('uid'))
    if update_uid in uid_list:
        for k, v in req.items():
            data.get('users')[uid_list.index(update_uid)][k] = v
        update_data('users.json', data)
        resp = {
            'errorCode': 0,
            'msg': 'uid {} has been updated'.format(update_uid)
        }
        status_code = 200
    elif not update_uid:
        resp = {
            'errorCode': 3,
            'msg': 'uid is required'
        }
        status_code = 401
    else:
        resp = {
            'errorCode': 1,
            'msg': 'uid {} not found'.format(update_uid)
        }
        status_code = 404

    return make_resp(resp, status_code)


@app.route('/api/users', methods=['DELETE'])
@validate_login
@validate_request
def del_user():
    req = request.get_json()
    del_uid = req.get('uid', None)
    data = get_data('users.json')
    users_list = data.get('users')
    uid_list = []
    for u in users_list:
        uid_list.append(u.get('uid'))
    if del_uid in uid_list:
        index = uid_list.index(del_uid)
        data['users'].pop(index)
        update_data('users.json', data)
        resp = {
            'errorCode': 0,
            'msg': 'uid {} has droped'.format(del_uid)
        }
        status_code = 200
    elif not del_uid:
        resp = {
            'errorCode': 3,
            'msg': 'uid is required'
        }
        status_code = 401
    else:
        resp = {
            'errorCode': 1,
            'msg': 'uid {} not found'.format(del_uid)
        }
        status_code = 404

    return make_resp(resp, status_code)


if __name__ == '__main__':
    pass
    app.run('0.0.0.0')
